﻿#pragma once
#include "stdafx.h"

namespace mcanvas
{
	struct Matrix
	{
		float T[16];
	public:
		Matrix()
		{
			identity();
		}
		~Matrix() {};
		void copy(const float m[16])
		{
			copy(T, m);
		}
		void identity()
		{
			const static float t[16] = {
				1.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 1.0f, 0.0f, 0.0f,
				0.0f, 0.0f, 1.0f, 0.0f,
				0.0f, 0.0f, 0.0f, 1.0f };
			copy(T, t);
		}
		void create_ortho(float left, float right, float bottom, float top, float zNear, float zFar)
		{
			const float invWidth = 1.0f / (right - left);
			const float invHeight = 1.0f / (top - bottom);
			const float invDepth = 1.0f / (zFar - zNear);
			identity();
			T[0 * 4 + 0] = 2.0f * invWidth;
			T[1 * 4 + 1] = 2.0f * invHeight;
			T[2 * 4 + 2] = -2.0f * invDepth;
			T[3 * 4 + 0] = -(right + left) * invWidth;
			T[3 * 4 + 1] = -(top + bottom) * invHeight;
			T[3 * 4 + 2] = -(zFar + zNear) * invDepth;
		}
		void create_perspective(float fov, float aspect, float zNear, float zFar)
		{
			const float PI = 3.14159265f;
			const float half_h = tan(fov / 180 * PI) * zNear;
			const float half_w = half_h * aspect;
			//////////////////////////////////////////////////////
			const float l = -half_w;
			const float r =  half_w;
			const float b = -half_h;
			const float t =  half_h;
			const float n = zNear;
			const float f = zFar;
			//////////////////////////////////////////////////////
			identity();

			T[0 * 4 + 0] = 2.0f*n /(r-l);
			T[1 * 4 + 1] = 2.0f*n /(t-b);
			T[2 * 4 + 2] = -(f+n)/(f-n);

			T[2 * 4 + 0] = (r + l) / (r - l);
			T[2 * 4 + 1] = (t + b) / (t - b);
			T[3 * 4 + 2] = -(2.0f*f*n) / (f - n);
			T[2 * 4 + 3] = -1.0f;
		}
		void inverse()
		{
			float t[16];
			copy(t, T);
			//det(行列式)
			float det =
				+t[3 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 2] * t[0 * 4 + 3] - t[2 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 2] * t[0 * 4 + 3]
				- t[3 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 2] * t[0 * 4 + 3] + t[1 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 2] * t[0 * 4 + 3]
				+ t[2 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 2] * t[0 * 4 + 3] - t[1 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 2] * t[0 * 4 + 3]
				- t[3 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 2] * t[1 * 4 + 3] + t[2 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 2] * t[1 * 4 + 3]
				+ t[3 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 2] * t[1 * 4 + 3] - t[0 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 2] * t[1 * 4 + 3]
				- t[2 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 2] * t[1 * 4 + 3] + t[0 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 2] * t[1 * 4 + 3]
				+ t[3 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 2] * t[2 * 4 + 3] - t[1 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 2] * t[2 * 4 + 3]
				- t[3 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 2] * t[2 * 4 + 3] + t[0 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 2] * t[2 * 4 + 3]
				+ t[1 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 2] * t[2 * 4 + 3] - t[0 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 2] * t[2 * 4 + 3]
				- t[2 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 2] * t[3 * 4 + 3] + t[1 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 2] * t[3 * 4 + 3]
				+ t[2 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 2] * t[3 * 4 + 3] - t[0 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 2] * t[3 * 4 + 3]
				- t[1 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 2] * t[3 * 4 + 3] + t[0 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 2] * t[3 * 4 + 3];
			//计算伴随矩阵
			T[0 * 4 + 0] = t[2 * 4 + 1] * t[3 * 4 + 2] * t[1 * 4 + 3] - t[3 * 4 + 1] * t[2 * 4 + 2] * t[1 * 4 + 3] + t[3 * 4 + 1] * t[1 * 4 + 2] * t[2 * 4 + 3] - t[1 * 4 + 1] * t[3 * 4 + 2] * t[2 * 4 + 3] - t[2 * 4 + 1] * t[1 * 4 + 2] * t[3 * 4 + 3] + t[1 * 4 + 1] * t[2 * 4 + 2] * t[3 * 4 + 3];
			T[1 * 4 + 0] = t[3 * 4 + 0] * t[2 * 4 + 2] * t[1 * 4 + 3] - t[2 * 4 + 0] * t[3 * 4 + 2] * t[1 * 4 + 3] - t[3 * 4 + 0] * t[1 * 4 + 2] * t[2 * 4 + 3] + t[1 * 4 + 0] * t[3 * 4 + 2] * t[2 * 4 + 3] + t[2 * 4 + 0] * t[1 * 4 + 2] * t[3 * 4 + 3] - t[1 * 4 + 0] * t[2 * 4 + 2] * t[3 * 4 + 3];
			T[2 * 4 + 0] = t[2 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 3] - t[3 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 3] + t[3 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 3] - t[1 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 3] - t[2 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 3] + t[1 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 3];
			T[3 * 4 + 0] = t[3 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 2] - t[2 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 2] - t[3 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 2] + t[1 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 2] + t[2 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 2] - t[1 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 2];
			T[0 * 4 + 1] = t[3 * 4 + 1] * t[2 * 4 + 2] * t[0 * 4 + 3] - t[2 * 4 + 1] * t[3 * 4 + 2] * t[0 * 4 + 3] - t[3 * 4 + 1] * t[0 * 4 + 2] * t[2 * 4 + 3] + t[0 * 4 + 1] * t[3 * 4 + 2] * t[2 * 4 + 3] + t[2 * 4 + 1] * t[0 * 4 + 2] * t[3 * 4 + 3] - t[0 * 4 + 1] * t[2 * 4 + 2] * t[3 * 4 + 3];
			T[1 * 4 + 1] = t[2 * 4 + 0] * t[3 * 4 + 2] * t[0 * 4 + 3] - t[3 * 4 + 0] * t[2 * 4 + 2] * t[0 * 4 + 3] + t[3 * 4 + 0] * t[0 * 4 + 2] * t[2 * 4 + 3] - t[0 * 4 + 0] * t[3 * 4 + 2] * t[2 * 4 + 3] - t[2 * 4 + 0] * t[0 * 4 + 2] * t[3 * 4 + 3] + t[0 * 4 + 0] * t[2 * 4 + 2] * t[3 * 4 + 3];
			T[2 * 4 + 1] = t[3 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 3] - t[2 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 3] - t[3 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 3] + t[0 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 3] + t[2 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 3] - t[0 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 3];
			T[3 * 4 + 1] = t[2 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 2] - t[3 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 2] + t[3 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 2] - t[0 * 4 + 0] * t[3 * 4 + 1] * t[2 * 4 + 2] - t[2 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 2] + t[0 * 4 + 0] * t[2 * 4 + 1] * t[3 * 4 + 2];
			T[0 * 4 + 2] = t[1 * 4 + 1] * t[3 * 4 + 2] * t[0 * 4 + 3] - t[3 * 4 + 1] * t[1 * 4 + 2] * t[0 * 4 + 3] + t[3 * 4 + 1] * t[0 * 4 + 2] * t[1 * 4 + 3] - t[0 * 4 + 1] * t[3 * 4 + 2] * t[1 * 4 + 3] - t[1 * 4 + 1] * t[0 * 4 + 2] * t[3 * 4 + 3] + t[0 * 4 + 1] * t[1 * 4 + 2] * t[3 * 4 + 3];
			T[1 * 4 + 2] = t[3 * 4 + 0] * t[1 * 4 + 2] * t[0 * 4 + 3] - t[1 * 4 + 0] * t[3 * 4 + 2] * t[0 * 4 + 3] - t[3 * 4 + 0] * t[0 * 4 + 2] * t[1 * 4 + 3] + t[0 * 4 + 0] * t[3 * 4 + 2] * t[1 * 4 + 3] + t[1 * 4 + 0] * t[0 * 4 + 2] * t[3 * 4 + 3] - t[0 * 4 + 0] * t[1 * 4 + 2] * t[3 * 4 + 3];
			T[2 * 4 + 2] = t[1 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 3] - t[3 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 3] + t[3 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 3] - t[0 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 3] - t[1 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 3] + t[0 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 3];
			T[3 * 4 + 2] = t[3 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 2] - t[1 * 4 + 0] * t[3 * 4 + 1] * t[0 * 4 + 2] - t[3 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 2] + t[0 * 4 + 0] * t[3 * 4 + 1] * t[1 * 4 + 2] + t[1 * 4 + 0] * t[0 * 4 + 1] * t[3 * 4 + 2] - t[0 * 4 + 0] * t[1 * 4 + 1] * t[3 * 4 + 2];
			T[0 * 4 + 3] = t[2 * 4 + 1] * t[1 * 4 + 2] * t[0 * 4 + 3] - t[1 * 4 + 1] * t[2 * 4 + 2] * t[0 * 4 + 3] - t[2 * 4 + 1] * t[0 * 4 + 2] * t[1 * 4 + 3] + t[0 * 4 + 1] * t[2 * 4 + 2] * t[1 * 4 + 3] + t[1 * 4 + 1] * t[0 * 4 + 2] * t[2 * 4 + 3] - t[0 * 4 + 1] * t[1 * 4 + 2] * t[2 * 4 + 3];
			T[1 * 4 + 3] = t[1 * 4 + 0] * t[2 * 4 + 2] * t[0 * 4 + 3] - t[2 * 4 + 0] * t[1 * 4 + 2] * t[0 * 4 + 3] + t[2 * 4 + 0] * t[0 * 4 + 2] * t[1 * 4 + 3] - t[0 * 4 + 0] * t[2 * 4 + 2] * t[1 * 4 + 3] - t[1 * 4 + 0] * t[0 * 4 + 2] * t[2 * 4 + 3] + t[0 * 4 + 0] * t[1 * 4 + 2] * t[2 * 4 + 3];
			T[2 * 4 + 3] = t[2 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 3] - t[1 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 3] - t[2 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 3] + t[0 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 3] + t[1 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 3] - t[0 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 3];
			T[3 * 4 + 3] = t[1 * 4 + 0] * t[2 * 4 + 1] * t[0 * 4 + 2] - t[2 * 4 + 0] * t[1 * 4 + 1] * t[0 * 4 + 2] + t[2 * 4 + 0] * t[0 * 4 + 1] * t[1 * 4 + 2] - t[0 * 4 + 0] * t[2 * 4 + 1] * t[1 * 4 + 2] - t[1 * 4 + 0] * t[0 * 4 + 1] * t[2 * 4 + 2] + t[0 * 4 + 0] * t[1 * 4 + 1] * t[2 * 4 + 2];
			//得到逆矩阵
			for (int i = 0; i < 16; i++)
				T[i] /= det;
		}
		void prepend(const Matrix &m)
		{
			static float tem[16];
			copy(tem, this->T);
			copy(this->T, m.T);
			mult(this->T, tem);
		}
		void mult(const Matrix &m)
		{
			mult(T, m.T);
		}
		void translate(const float &x, const float &y)
		{
			const float t[16] = {  //行主
				1.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 1.0f, 0.0f, 0.0f,
				0.0f, 0.0f, 1.0f, 0.0f,
				   x,    y, 0.0f, 1.0f };
			mult(T, t);
		}
		void rotate(const float &angle/*角度制*/)
		{
			float a = angle * 0.01745329f;
			float t[16] = { /*行主*/
				cos(a),  sin(a), 0.0, 0.0,
				-sin(a), cos(a), 0.0, 0.0,
				0.0,       0.0 , 1.0, 0.0,
				0.0,       0.0 , 0.0, 1.0 };
			mult(T, t);
		}
		void scale(const float &x, const float &y)
		{
			float t[16] = {
				  x , 0.0f, 0.0f, 0.0f,
				0.0f,   y , 0.0f, 0.0f,
				0.0f, 0.0f, 1.0f, 0.0f,
				0.0f, 0.0f, 0.0f, 1.0f };
			mult(T, t);
		}
		void transform(Point &pt) const
		{
			float tx = float(pt.X * T[0] + pt.Y * T[4] + T[12]);
			float ty = float(pt.X * T[1] + pt.Y * T[5] + T[13]);
			float  w = float(pt.X * T[3] + pt.Y * T[7] + T[15]);
			pt.X = tx / w;
			pt.Y = ty / w;
		}
		void transform(std::vector<Point> &data) const
		{
			for (int i = 0; i<int(data.size()); i++)
				transform(data[i]);
		}
		void transform(std::vector<std::vector<Point>> &data) const
		{
			for (int i = 0; i<int(data.size()); i++)
			for (int j = 0; j<int(data[i].size()); j++)
				transform(data[i][j]);
		}
	private:
		void copy(float M[16], const float m[16])
		{
			for (int i = 0; i < 16; i++)
				M[i] = m[i];
		}
		void mult(float M[16], const float m[16])
		{
			float c[16];
			c[0] = M[0] * m[0] + M[4] * m[1] + M[8] * m[2] + M[12] * m[3];
			c[1] = M[1] * m[0] + M[5] * m[1] + M[9] * m[2] + M[13] * m[3];
			c[2] = M[2] * m[0] + M[6] * m[1] + M[10] * m[2] + M[14] * m[3];
			c[3] = M[3] * m[0] + M[7] * m[1] + M[11] * m[2] + M[15] * m[3];
			c[4] = M[0] * m[4] + M[4] * m[5] + M[8] * m[6] + M[12] * m[7];
			c[5] = M[1] * m[4] + M[5] * m[5] + M[9] * m[6] + M[13] * m[7];
			c[6] = M[2] * m[4] + M[6] * m[5] + M[10] * m[6] + M[14] * m[7];
			c[7] = M[3] * m[4] + M[7] * m[5] + M[11] * m[6] + M[15] * m[7];
			c[8] = M[0] * m[8] + M[4] * m[9] + M[8] * m[10] + M[12] * m[11];
			c[9] = M[1] * m[8] + M[5] * m[9] + M[9] * m[10] + M[13] * m[11];
			c[10] = M[2] * m[8] + M[6] * m[9] + M[10] * m[10] + M[14] * m[11];
			c[11] = M[3] * m[8] + M[7] * m[9] + M[11] * m[10] + M[15] * m[11];
			c[12] = M[0] * m[12] + M[4] * m[13] + M[8] * m[14] + M[12] * m[15];
			c[13] = M[1] * m[12] + M[5] * m[13] + M[9] * m[14] + M[13] * m[15];
			c[14] = M[2] * m[12] + M[6] * m[13] + M[10] * m[14] + M[14] * m[15];
			c[15] = M[3] * m[12] + M[7] * m[13] + M[11] * m[14] + M[15] * m[15];
			/*float c[16] = {
				0.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 0.0f, 0.0f, 0.0f };
			for (int j = 0; j < 4; j++)
			for (int i = 0; i < 4; i++)
			{
				float &cc = c[j * 4 + i];
				for (int k = 0; k < 4; k++)
					cc += M[k * 4 + i] * m[j * 4 + k];
			}*/
			copy(M, c);
		}
	};
}
